package com.example.armmvvm.ui.customdraw

import android.animation.AnimatorSet
import android.animation.Keyframe
import android.animation.ObjectAnimator
import android.animation.PropertyValuesHolder
import android.animation.ValueAnimator.INFINITE
import android.animation.ValueAnimator.REVERSE
import android.graphics.PointF
import android.os.Bundle
import android.view.LayoutInflater
import com.example.arm.base.BaseActivity
import com.example.arm.ext.dp
import com.example.arm.ext.dpInt
import com.example.arm.ext.toast
import com.example.arm.mvvm.IView
import com.example.arm.util.RxLifecycleUtils
import com.example.armmvvm.R
import com.example.armmvvm.databinding.ActivityCustomDrawBinding
import io.reactivex.Observable
import timber.log.Timber
import java.util.concurrent.TimeUnit
import kotlin.math.abs

/**
 * @author 创建人 ：yanghaozhang
 * @version 1.0
 * @package 包名 ：com.example.armmvvm.ui.customdraw.view
 * @createTime 创建时间 ：2022/2/16
 * @modifyBy 修改人 ：
 * @modifyTime 修改时间 ：
 * @modifyMemo 修改备注：
 */
class CustomDrawActivity : BaseActivity<ActivityCustomDrawBinding>() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // onCreate()方法,performMeasure(),performLayout()执行前,宽高度为0
        val testView = binding.viewPointF
        Timber.d("1---------${testView.width}----${testView.height}")
        binding.viewPointF.post {
            Timber.d("2---------${testView.width}----${testView.height}")
            binding.viewPointF.post {
                Timber.d("3---------${testView.width}----${testView.height}")
            }
            binding.viewPointF.layoutParams.height = 40.dpInt
            binding.viewPointF.requestLayout()
            binding.viewPointF.post {
                Timber.d("4---------${testView.width}----${testView.height}")
            }
            // 3和4为改变高度后的值
            // requestLayout()执行后,AttachInfo.mHandle其他任务将阻塞,优先performTraversals()的执行
        }
    }

    private var tipsChangeAnimatorSet: ObjectAnimator? = null

    override fun initView(savedInstanceState: Bundle?) =
        ActivityCustomDrawBinding.inflate(layoutInflater)

    override fun initData(savedInstanceState: Bundle?) {

        // 围绕img中心提起60度
//        canvasControl()

        // 动画
        animator()

        val inflate = LayoutInflater.from(this)
            .inflate(R.layout.layout_function_bottom_fall_view, binding.tagView, true)
        inflate.layoutParams
    }

    private fun animator() {
        // ViewPropertyAnimator 简单的属性动画,只适用于常见的缩放/移动等类型,无法对特定参数进行改变
        viewPropertyAnimator()

        // ObjectAnimator 在指定时间内改变一个变量为指定值,不一定是View,比如在1s内将topFlip的值变成-60
        // AnimatorSet 动画集合,既可以同时做,也可以按顺序做
//        objectAnimatorAndSet()

        // PropertyValuesHolder 用于创建具有并行操作的多个不同属性的动画
//        propertyValuesHolder()

        // PropertyValuesHolder & Keyframe 用于指定关键帧,从而指定不同的流程
        // 关键帧的两个值,fraction代表时间的百分比,value代表到达的值的大小
        // 关键帧能够设置差值器,配合TimeInterpolator使用
        keyframe()

        // PointFTypeEvaluator 通过类型计算类
        typeEvaluator()

        // 折叠ViewGroup
        changeViewGroupCollapsed()
    }

    private fun changeViewGroupCollapsed() {
        binding.tvCollapsed.setOnClickListener {
            tipsChangeAnimatorSet?.cancel()
            if (it.isSelected) {
                val time = abs(1f - binding.tagView.alpha) * 1500
                tipsChangeAnimatorSet =
                    ObjectAnimator.ofFloat(this, "viewAlpha", binding.tagView.alpha, 1f).apply {
                        duration = time.toLong()
                        start()
                    }
            } else {
                val time = abs(binding.tagView.alpha) * 1500
                tipsChangeAnimatorSet =
                    ObjectAnimator.ofFloat(this, "viewAlpha", binding.tagView.alpha, 0f).apply {
                        duration = time.toLong()
                        start()
                    }
            }
            it.isSelected = !it.isSelected
        }
    }

    fun setViewAlpha(alpha: Float) {
        binding.tagView.alpha = alpha
        // 不能通过改变ScaleY来折叠,View的高度不会改变,底下的View不会上来
        binding.tagView.layoutParams = binding.tagView.layoutParams.apply {
            // 需要一个确定的值来作为高度
            height = (100.dp * alpha).toInt()
        }
    }

    private fun typeEvaluator() {
        ObjectAnimator.ofObject(
            binding.viewPointF,
            "point",
            PointFTypeEvaluator(),
            PointF(100.dp, 100.dp)
        ).apply {
            startDelay = 200
            duration = 1000
            repeatMode = REVERSE
            repeatCount = INFINITE
            start()
        }

        ObjectAnimator.ofInt(binding.viewPointF, "countText", 1000, 10000).apply {
            startDelay = 200
            duration = 10000
            start()
        }
    }

    private fun keyframe() {
        binding.viewImageAngle.bottomFlip = 60f
        val flipRotationTarget = 100.dp
        val time = 10_000L
        // 将flipRotation从0f~360f分成了3段
        // 第一段,时间:0.2,值:0~0.2,中等
        // 第二段,时间:0.4,值:0.2~0.9,最快
        // 第三段,时间:0.4,值:0.9~1,最慢
        val keyFrame1 = Keyframe.ofFloat(0f, 0f)
        val keyFrame2 = Keyframe.ofFloat(0.2f, 0.2f * flipRotationTarget)
        val keyFrame3 = Keyframe.ofFloat(0.6f, 0.9f * flipRotationTarget)
        val keyFrame4 = Keyframe.ofFloat(1f, 1f * flipRotationTarget)
        val topFlipHolder = PropertyValuesHolder.ofKeyframe(
            "flipRotation",
            keyFrame1,
            keyFrame2,
            keyFrame3,
            keyFrame4
        )
        ObjectAnimator.ofPropertyValuesHolder(binding.viewImageAngle, topFlipHolder).apply {
            startDelay = 200
            duration = time
            start()
        }
    }

    private fun propertyValuesHolder() {
        val topFlipHolder = PropertyValuesHolder.ofFloat("topFlip", -60f)
        val bottomFlipHolder = PropertyValuesHolder.ofFloat("bottomFlip", 60f)
        val flipRotationHolder = PropertyValuesHolder.ofFloat("flipRotation", 270f)
        ObjectAnimator.ofPropertyValuesHolder(
            binding.viewImageAngle,
            topFlipHolder,
            bottomFlipHolder,
            flipRotationHolder
        ).apply {
            startDelay = 200
            duration = 1000
            start()
        }
    }

    private fun objectAnimatorAndSet() {
        // ObjectAnimator 在指定时间内改变一个变量为指定值,不一定是View,比如在1s内将topFlip的值变成-60
        val topFlipAnimator =
            ObjectAnimator.ofFloat(binding.viewImageAngle, "topFlip", -60f).apply {
                startDelay = 200
                duration = 1000
            }

        val bottomFlipAnimator =
            ObjectAnimator.ofFloat(binding.viewImageAngle, "bottomFlip", 60f).apply {
                startDelay = 200
                duration = 1000
            }

        val flipRotationAnimator =
            ObjectAnimator.ofFloat(binding.viewImageAngle, "flipRotation", 270f).apply {
                startDelay = 200
                duration = 1000
            }

        // AnimatorSet 动画集合,既可以同时做,也可以按顺序做
        AnimatorSet().apply {
            playSequentially(bottomFlipAnimator, flipRotationAnimator, topFlipAnimator)
//            playTogether(bottomFlipAnimator, flipRotationAnimator, topFlipAnimator)
            start()
        }
    }

    private fun viewPropertyAnimator() {
        // 改变的实际上是setTranslationY()等的数据,修改的是Canvas绘制时添加的转换,不会改变在ViewGroup的params值,需要进行区分
        // 比如:setTranslationY(),实际并未改变布局边界,只是绘制范围拓展到整个父布局,如果父布局有空间,则会绘制出来,如果没有空间或有其他子View,则会被覆盖
        // 属性动画:View的动画虽然无法超出Parent的边界,也会被其他的View所覆盖,但是触摸范围也随其执行动画后的绘制范围而变化
        binding.squareView.animate()
            .translationY(20.dp)
            .scaleY(0.5f)
            .scaleX(0.5f)
            .setDuration(3000)
            // 绘制时使用离屏缓冲,只能在自带通用动画上才能使用.这是官方的优化,让动画更流畅
            .withLayer()
            .setStartDelay(1000)
            .start()
        // 点击其绘制范围
        binding.squareView.setOnClickListener {
            toast("it is click")
        }
    }

    private fun canvasControl() {
        // 围绕img中心提起60度
        binding.viewImageAngle.bottomFlip = 60f
        val subscribe = Observable.interval(0, 40, TimeUnit.MILLISECONDS)
            .compose(RxLifecycleUtils.bindToLifecycle(this as IView))
            .subscribe {
                val angle = it % 360
                Timber.d("---$it---")
                binding.viewImageAngle.flipRotation = angle.toFloat()
            }
    }
}